using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

using DirectShowLib;
using LeisureCenter.Api;

namespace DirectShowPlayer
{
    public class BaseDirectShowMedia : BasePositionableMedia
    {
        private const int VolumeFull = 0;
        private const int VolumeSilence = -10000;

        protected DirectShowPlayer player;

        //private int currentVolume = VolumeFull;

        protected IGraphBuilder graphBuilder;
        protected IMediaControl mediaControl;
        protected IMediaEventEx mediaEventEx;
        protected IBasicAudio basicAudio;
        protected IBasicVideo basicVideo;
        protected IMediaSeeking _mediaSeeking;
        protected IMediaPosition mediaPosition;
        protected IVideoFrameStep frameStep;

        public BaseDirectShowMedia(DirectShowPlayer player, string fileName)
            : base(fileName)
        {
            this.player = player;
        }

        protected virtual void CloseInterfaces()
        {
            int hr = 0;

            try
            {
                lock (this)
                {
                    if (this.mediaEventEx != null)
                    {
                        hr = this.mediaEventEx.SetNotifyWindow(IntPtr.Zero, 0, IntPtr.Zero);
                        DsError.ThrowExceptionForHR(hr);
                    }

                    // Release and zero DirectShow interfaces
                    if (this.mediaEventEx != null)
                        this.mediaEventEx = null;
                    if (this._mediaSeeking != null)
                        this._mediaSeeking = null;
                    if (this.mediaPosition != null)
                        this.mediaPosition = null;
                    if (this.mediaControl != null)
                        this.mediaControl = null;
                    if (this.basicAudio != null)
                        this.basicAudio = null;
                    if (this.basicVideo != null)
                        this.basicVideo = null;
                    if (this.frameStep != null)
                        this.frameStep = null;
                    if (this.graphBuilder != null)
                        Marshal.ReleaseComObject(this.graphBuilder); this.graphBuilder = null;

                    GC.Collect();
                }
            }
            catch
            {
            }
        }

        #region IMedia implementation

        public override MediaKind Kind
        {
            get { return MediaKind.Music; }
        }

        #endregion

        #region IPositionableMedia implementation

        public override int Duration
        {
            get
            {
                double time = 0;
                if (mediaPosition != null)
                    mediaPosition.get_Duration(out time);
                return (int)time;
            }
        }

        public override int Position
        {
            get
            {
                double time = 0;
                if (mediaPosition != null)
                    mediaPosition.get_CurrentPosition(out time);
                return (int)time;
            }

            set
            {
                if (mediaPosition != null)
                    mediaPosition.put_CurrentPosition((double)value);
            }
        }

        protected virtual void CreateFilterGraph()
        {
            int hr = 0;

            this.graphBuilder = (IGraphBuilder)new FilterGraph();

            // Have the graph builder construct its the appropriate graph automatically
            hr = this.graphBuilder.RenderFile(FileName, null);
            DsError.ThrowExceptionForHR(hr);

        }

        protected override void OpenFile()
        {
            if (string.IsNullOrEmpty(FileName))
                return;

            try
            {
                CreateFilterGraph();

                // QueryInterface for DirectShow interfaces
                this.mediaControl = (IMediaControl)this.graphBuilder;
                this.mediaEventEx = (IMediaEventEx)this.graphBuilder;
                this._mediaSeeking = (IMediaSeeking)this.graphBuilder;
                this.mediaPosition = (IMediaPosition)this.graphBuilder;

                // Query for audio interfaces, which may not be relevant for video-only files
                this.basicAudio = this.graphBuilder as IBasicAudio;

                // Have the graph signal event via window callbacks for performance
                //hr = this.mediaEventEx.SetNotifyWindow(this.Handle, WMGraphNotify, IntPtr.Zero);
                //DsError.ThrowExceptionForHR(hr);
            }
            catch (Exception ex)
            {
                LoadingState = MediaLoadingState.Error;
                loadingErrorMessage = ex.Message;
            }
        }

        protected override void DoPlay()
        {
            if (mediaControl != null && mediaControl.Run() >= 0)
                base.DoPlay();
        }

        protected override void DoPause()
        {
            if (mediaControl != null && mediaControl.Pause() >= 0)
                base.DoPause();
        }

        protected override void DoStop()
        {
            int hr = 0;

            // Stop media playback
            if (mediaControl != null)
                hr = mediaControl.Stop();

            PlayState = MediaPlayState.Stopped;

            // Free DirectShow interfaces
            try
            {
                CloseInterfaces();
            }
            catch (Exception ex)
            {
                LoadingState = MediaLoadingState.Error;
                loadingErrorMessage = ex.Message;
            }
        }
        #endregion

    }
}
